home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / checkbox / lib / process.py < prev    next >
Encoding:
Python Source  |  2009-04-27  |  4.4 KB  |  114 lines

  1. #
  2. # This file is part of Checkbox.
  3. #
  4. # Copyright 2008 Canonical Ltd.
  5. #
  6. # Checkbox is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # Checkbox is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with Checkbox.  If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. import os
  20. import time
  21. import select
  22.  
  23.  
  24. class Process:
  25.     """Class representing a child process which is non blocking. This makes
  26.        it possible to return within a specified timeout."""
  27.  
  28.     def __init__(self, cmd, env={}, bufsize=8192):
  29.         """The parameter 'cmd' is the shell command to execute in a
  30.         sub-process. If the 'bufsize' parameter is specified, it
  31.         specifies the size of the I/O buffers from the child process."""
  32.         self.cleaned=False
  33.         self.BUFSIZ=bufsize
  34.         self.outr, self.outw = os.pipe()
  35.         self.errr, self.errw = os.pipe()
  36.         self.pid = os.fork()
  37.         if self.pid == 0:
  38.             self._child(cmd, env)
  39.         os.close(self.outw) #parent doesn't write so close
  40.         os.close(self.errw)
  41.         # Note we could use self.stdout=fdopen(self.outr) here
  42.         # to get a higher level file object like popen2.Popen3 uses.
  43.         # This would have the advantages of auto handling the BUFSIZ
  44.         # and closing the files when deleted. However it would mean
  45.         # that it would block waiting for a full BUFSIZ unless we explicitly
  46.         # set the files non blocking, and there would be extra uneeded
  47.         # overhead like EOL conversion. So I think it's handier to use os.read()
  48.         self.outdata = self.errdata = ""
  49.         self.starttime = self.endtime = None
  50.         self._outeof = self._erreof = 0
  51.  
  52.     def _child(self, cmd, env):
  53.         # Note sh below doesn't setup a seperate group (job control)
  54.         # for non interactive shells (hmm maybe -m option does?)
  55.         os.setpgrp() #seperate group so we can kill it
  56.         os.dup2(self.outw,1) #stdout to write side of pipe
  57.         os.dup2(self.errw,2) #stderr to write side of pipe
  58.         #stdout & stderr connected to pipe, so close all other files
  59.         map(os.close, [self.outr,self.outw,self.errr,self.errw])
  60.         try:
  61.             cmd = ["/bin/sh", "-c", cmd]
  62.             os.execve(cmd[0], cmd, env)
  63.         finally: #exit child on error
  64.             os._exit(1)
  65.  
  66.     def read(self, timeout=None):
  67.         """return 0 when finished
  68.            else return 1 every timeout seconds
  69.            data will be in outdata and errdata"""
  70.         self.starttime = time.time()
  71.         while 1:
  72.             tocheck=[]
  73.             if not self._outeof:
  74.                 tocheck.append(self.outr)
  75.             if not self._erreof:
  76.                 tocheck.append(self.errr)
  77.             ready = select.select(tocheck, [], [], timeout)
  78.             if len(ready[0]) == 0: #no data timeout
  79.                 return 1
  80.             else:
  81.                 if self.outr in ready[0]:
  82.                     outchunk = os.read(self.outr, self.BUFSIZ)
  83.                     if outchunk == "":
  84.                         self._outeof = 1
  85.                     self.outdata += outchunk
  86.                 if self.errr in ready[0]:
  87.                     errchunk = os.read(self.errr, self.BUFSIZ)
  88.                     if errchunk == "":
  89.                         self._erreof = 1
  90.                     self.errdata += errchunk
  91.                 if self._outeof and self._erreof:
  92.                     self.endtime = time.time()
  93.                     return 0
  94.                 elif timeout:
  95.                     if (time.time() - self.starttime) > timeout:
  96.                         return 1 # may be more data but time to go
  97.  
  98.     def kill(self):
  99.         os.kill(-self.pid, 15) # SIGTERM whole group
  100.  
  101.     def cleanup(self):
  102.         """Wait for and return the exit status of the child process."""
  103.         self.cleaned = True
  104.         os.close(self.outr)
  105.         os.close(self.errr)
  106.         pid, status = os.waitpid(self.pid, 0)
  107.         if pid == self.pid:
  108.             self.status = status
  109.         return self.status
  110.  
  111.     def __del__(self):
  112.         if not self.cleaned:
  113.             self.cleanup()
  114.